//
// Copyright (c) 2020, Intel Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// Neither the name of the Intel Corporation nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

//
// Translate CCI-P read (c0) requests from virtual addresses using VTP.
//

`include "ofs_plat_if.vh"
`include "cci_mpf_if.vh"

module mpf_vtp_translate_ofs_ccip_c0
   (
    input  logic clk,
    input  logic reset,

    output t_if_ccip_c0_Tx c0_host,
    input  logic c0_host_almostFull,

    // Request: commands to VTP (e.g. address is virtual)
    input  mpf_vtp_pkg::t_mpf_vtp_port_wrapper_req vtp_req,
    input  t_if_ccip_c0_Tx c0_va,
    output logic vtp_req_almostFull,

    // Response from VTP (e.g. whether translation was successful)
    output mpf_vtp_pkg::t_mpf_vtp_port_wrapper_rsp vtp_rsp,
    mpf_vtp_port_if.to_slave vtp_port
    );

    import mpf_vtp_pkg::*;

    logic vtp_notFull;
    logic vtp_outValid;
    t_if_ccip_c0_Tx c0_outTx;
    logic vtp_deq_en;
    t_mpf_vtp_req_tag vtp_reqIdx;
    t_mpf_vtp_req_tag vtp_rspIdx;

    //
    // Request FIFO for handling almost full
    //
    mpf_vtp_pkg::t_mpf_vtp_port_wrapper_req vtp_req_buf;
    t_if_ccip_c0_Tx c0_va_buf;
    logic req_notEmpty;

    cci_mpf_prim_fifo_lutram
      #(
        .N_DATA_BITS($bits(vtp_req) + $bits(c0_va)),
        .N_ENTRIES(CCI_TX_ALMOST_FULL_THRESHOLD + 4),
        .THRESHOLD(CCI_TX_ALMOST_FULL_THRESHOLD),
        .REGISTER_OUTPUT(1)
        )
      c0_fifo
       (
        .clk,
        .reset,

        .enq_data({ vtp_req, c0_va }),
        // Map the valid bit through as enq here and notEmpty below.
        .enq_en(c0_va.valid),
        .notFull(),
        .almostFull(vtp_req_almostFull),

        .first({ vtp_req_buf, c0_va_buf }),
        .deq_en(process_new_req),
        .notEmpty(req_notEmpty)
        );


    logic process_new_req;
    assign process_new_req = req_notEmpty && vtp_notFull;

    // Do the translation, allowing responses out of order (the usual for CCI-P).
    // VTP assigns the request a unique ID while in flight (reqIdx). The
    // ID will be returned with the response (rspIdx), making it easy to
    // manage storage of request meta-data.
    mpf_svc_vtp_port_wrapper_unordered
      tr_c0
       (
        .clk,
        .reset,

        .vtp_port,
        .reqEn(process_new_req),
        .req(vtp_req_buf),
        .notFull(vtp_notFull),
        .reqIdx(vtp_reqIdx),

        .rspValid(vtp_outValid),
        .rsp(vtp_rsp),
        .rspDeqEn(vtp_deq_en),
        .rspIdx(vtp_rspIdx)
        );

    // Hold the full c0Tx request during lookup. The VTP port wrapper provides
    // up to MPF_VTP_MAX_SVC_REQS indices. The addresses used for storage are
    // generated by the VTP port as part of its request tracking logic.
    cci_mpf_prim_lutram
      #(
        .N_ENTRIES(MPF_VTP_MAX_SVC_REQS),
        .N_DATA_BITS($bits(c0_va_buf))
        )
      tr_c0_meta
       (
        .clk,
        .reset,

        .raddr(vtp_rspIdx),
        .rdata(c0_outTx),

        .wen(process_new_req),
        .waddr(vtp_reqIdx),
        .wdata(c0_va_buf)
        );

    // Accept VTP responses as long as there is space in the host channel
    assign vtp_deq_en = vtp_outValid && ! c0_host_almostFull;

    // Route translated reads to the FIU. vtp_rsp may signal an error.
    always_comb
    begin
        c0_host = c0_outTx;
        c0_host.valid = vtp_deq_en;

        // Set the address to the translated result.
        c0_host.hdr.address = vtp_rsp.addr;
    end


    //
    // Debugging
    //

    // synthesis translate_off
    always_ff @(posedge clk)
    begin
        if (! reset)
        begin
            if (vtp_deq_en && vtp_rsp.error)
            begin
                $display("%m VTP: %0t Translation error from VA 0x%x",
                         $time,
                         {c0_outTx.hdr.address, 6'b0});
            end
        end
    end
    // synthesis translate_on

endmodule // mpf_vtp_translate_ofs_ccip_c0
